package supermarket;

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.TypedQuery;

import model.Bank;
import model.CheckCard;
import model.CreditCard;
import model.Customer;
import model.Product;
import model.ProductPurchase;
import model.Purchase;
import model.Store;
import modelx.CreditCardAuthority;
import modelx.ExternalBank;

import GUI.LoginOrThreadsForm;
import GUI.LoginForm;

import javax.swing.JFrame;
import javax.swing.JMenu;

        

/**
 *
 * @author Nicolas Drosos
 */
public class SuperMarket {

    // O entity manager 
    private static EntityManager em;
    private static EntityManager em2;
    // Το όριο πόντων της κάρτας στο οποίο ο πελάτης κερδίζει μια επιταγή
    public static final int CHECK_POINTS_LIMIT = 200;
    
    private LoginOrThreadsForm loginOrThreadsForm;
    private LoginForm loginForm;
    
    

    public SuperMarket() {
        // Δημιουργία ΤΩΝ Entity Manager
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("SuperMarketPU");
        em = emf.createEntityManager();
        EntityManagerFactory emf2 = Persistence.createEntityManagerFactory("CreditCardAuthPU");
        em2 = emf2.createEntityManager();

        this.loginOrThreadsForm = new LoginOrThreadsForm(this);
        this.loginForm = new LoginForm(this);
    }

    public EntityManager getEm() {
        return em;
    }
    public EntityManager getEm2() {
        return em2;
    }
    
    // Καθαρίζει όλους τους πίνακες της ΒΔ
    private void clearDB() {
        em.getTransaction().begin();
        try {
            Query q = em.createQuery("DELETE FROM ProductPurchase pp");
            q.executeUpdate();
            q = em.createQuery("DELETE FROM Product p");
            q.executeUpdate();
            q = em.createQuery("DELETE FROM Purchase pu");
            q.executeUpdate();
            q = em.createQuery("DELETE FROM Store s");
            q.executeUpdate();
            q = em.createQuery("DELETE FROM Customer c");
            q.executeUpdate();

            em.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
            em.getTransaction().rollback();
        }
    }

    /**
     * Δημιουργεί 10 προϊόντα και 2 καταστήματα. Στη συνέχεια καθορίζει τα
     * προϊόντα που εμπορεύεται κάθε κατάστημα και τα αποθηκεύει στη ΒΔ.
     */
    public void createStoresAndProducts() {
        // αρχικοποίηση transaction
        em.getTransaction().begin();
        try {
            // Δημιουργία 10 διαφορετικών αντικειμένων Product. Η κατάσταση των Product entities
            // είναι 'Νέο' καθώς δεν έχουν γίνει ακόμα managed από τον entity manager
            // στο persistence context 
            Product spagheti = new Product("Μακαρόνια No7", "11111", 10, 1.20f);
            Product nescafe = new Product("Καφές 500gr", "22222", 12, 3.20f);
            Product cleaning = new Product("Απορρυπαντικό Liquid 5lt", "33333", 20, 15.50f);
            Product oliveOil = new Product("Λάδι 5lt", "44444", 6, 10.30f);
            Product bath = new Product("Bath oil", "55555", 4, 6.50f);
            Product tigani = new Product("Τηγάνι 30cm", "666666", 30, 20.0f);
            Product pet = new Product("Pet food", "77777", 6, 9.45f);
            Product beer = new Product("Beer 500mlx6", "88888", 5, 7.66f);
            Product alcoholDrink = new Product("Alcohol drink", "99999", 50, 36.77f);
            Product chocolateCake = new Product("Chocolate Cake", "00000", 2, 5.20f);

            // Δημιουργία 2 διαφορετικών αντικειμένων Store. 
            Store abAlimou = new Store("AB Αλίμου", "Καλαμακίου 120, Άλιμος");
            Store abFalirou = new Store("AB Φαλήρου", "Ποσειδώνος 300, Παλαιό Φάληρο");

            /**
             * Για να ορίσουμε τα προϊόντα που εμπορεύεται ένα κατάστημα,
             * δημιουργούμε μια λίστα και προσθέτουμε τα προϊόντα που θέλουμε σε
             * αυτή. Στη συνέχεια θέτουμε τη λίστα αυτή στο αντικείμενο Store. Η
             * σχέση Store-Product είναι many-to-many, δηλαδή αφενός το Store
             * έχει μια λίστα με Products, αφετέρου το Store έχει μια λίστα με
             * Stores.Επίσης έχουμε ορίσει CascadeType.ALL στη λίστα productList
             * της κλάσης Store. Αυτό σημαίνει ότι όλες οι αλλαγές άρα και η
             * δημιουργία ενός αντικειμένου Store θα προκαλέσει τη δημιουργία
             * και των αντίστοιχων αντικειμένων Product που βρίσκονται στη λίστα
             * του.
             *
             */
            List<Product> alimouList = new ArrayList<>();
            alimouList.add(spagheti);
            alimouList.add(nescafe);
            alimouList.add(cleaning);
            alimouList.add(oliveOil);
            alimouList.add(bath);
            alimouList.add(tigani);
            alimouList.add(pet);
            alimouList.add(chocolateCake);
            abAlimou.setProductList(alimouList);
            em.persist(abAlimou);

            // κάνουμε το ίδιο και για το άλλο κατάστημα
            List<Product> falirouList = new ArrayList<>();
            falirouList.add(spagheti);
            falirouList.add(nescafe);
            falirouList.add(cleaning);
            falirouList.add(oliveOil);
            falirouList.add(bath);
            falirouList.add(tigani);
            falirouList.add(beer);
            falirouList.add(alcoholDrink);
            abFalirou.setProductList(falirouList);
            em.persist(abFalirou);

            /**
             * Κάνοντας commit το transaction θα δημιουργηθούν οι αντίστοιχες
             * εγγραφές Store και Product στη ΒΔ ενώ τα αντίστοιχα αντικείμενα
             * θα γίνουν managed.
             */
            em.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
            em.getTransaction().rollback();
        }
    }

    /**
     * Δημιουργεί το κεντρικό μενού της εφαρμογής
     */
    public void displayMainMenu() {

        File xmlFile = new File("C:\\temp\\purchases.xml");
        PurchaseXMLManager purchaseXMLWriter = new PurchaseXMLManager(xmlFile);

    }

    /**
     * Επιστρέφει ένα ψευδο-τυχαίο αριθμό μεταξύ min και max.
     *
     *
     * @param min Η ελάχιστη τιμή
     * @param max Η μέγιστη τιμή η οποία πρέπει να είναι μεγαλύτερη από τη Min.
     * @return Ακέραιο μεταξύ min και max. *
     */
    private int randInt(int min, int max) {
        Random rand = new Random();
        int randomNum = rand.nextInt((max - min) + 1) + min;
        return randomNum;
    }

    /**
     * Εξάγει όλες τις αγορές που είναι αποθηκευμένες στη ΒΔ σε αρχείο XML στη
     * θέση C:\temp
     *
     * @param purchaseXMLWriter
     */
    private void exportPurchases(PurchaseXMLManager purchaseXMLWriter) {
        TypedQuery<Purchase> allPurchasesQuery = em.createNamedQuery("Purchase.findAll", Purchase.class);
        List<Purchase> purchaseResults = allPurchasesQuery.getResultList();
        purchaseXMLWriter.writeXML(purchaseResults);
        System.out.println("Το αρχείο XML δημιουργήθηκε με επιτυχία στο C:\\temp");
        try {
            em.getTransaction().begin();
            for (Purchase p : purchaseResults) {
                em.remove(p);
            }
            em.getTransaction().commit();
            System.out.println("Επιτυχής Διαγραφή συναλλαγών!");
            System.out.println(" ");
        } catch (Exception e) {
            e.printStackTrace();
            em.getTransaction().rollback();
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        SuperMarket sm = new SuperMarket();
        //Καθαρισμός Βάσης Δεδομένων
        sm.clearDB();
        //Δημιουργία καταστημάτων και προϊόντων
        sm.createStoresAndProducts();
        // Προβολή αρχικού παραθύρου
        sm.loginOrThreadsForm.setVisible(true);
    }

public JFrame gLoginForm() {
        return loginForm;
    }
}

